//
//  T3FMARouteManager.swift
//  t3_map
//
//  Created by Cunhai Li on 2024/12/10.
//

import Foundation
import AMapSearchKit
import Flutter

class T3FMARouteManager: NSObject {

    private let search = AMapSearchAPI()
    private var strongSelf: T3FMARouteManager?
    private var result: FlutterResult?

    /// 步行算路
    func walkRoute(arguments: Any?, result: @escaping FlutterResult) {
        self.result = result

        /// arguments示例：
        /// ```
        /// {
        ///     "origin": {
        ///         "longitude": 11.111
        ///         "latitude": 11.111
        ///    },
        ///    "destination": {
        ///         "longitude": 11.111
        ///         "latitude": 11.111
        ///    },
        /// }
        /// ```
        do {
            let json = try T3FJsonUtil.toJson(arguments)

            if let origin = jsonToCoordinate2D(key: "origin", json: json),
                let destination = jsonToCoordinate2D(key: "destination", json: json) {

                if let search = search {
                    //构建request
                    let request = AMapWalkingRouteSearchRequest()
                    request.origin = AMapGeoPoint.location(withLatitude: origin.latitude, longitude: origin.longitude)
                    request.destination = AMapGeoPoint.location(withLatitude: destination.latitude, longitude: destination.longitude)
                    request.showFieldsType = .polyline

                    /// 保持引用
                    strongSelf = self
                    search.delegate = self
                    search.aMapWalkingRouteSearch(request)
                }
                else {
                    let response = ["error": T3FMARouteManagerError.mapSearchInitFail.localizedDescription]
                    let value = try? T3FJsonUtil.toString(response)
                    self.result?(value)
                }
            }
            else {
                let response = ["error": T3FMARouteManagerError.dataParseFail.localizedDescription]
                let value = try? T3FJsonUtil.toString(response)
                self.result?(value)
            }
        } catch (let error) {
            let response = ["error": error.localizedDescription]
            let value = try? T3FJsonUtil.toString(response)
            self.result?(value)
        }
    }

    /// 驾车算路
    func driveRoute(arguments: Any?, result: @escaping FlutterResult) {
        self.result = result

        /// arguments示例：
        /// ```
        /// {
        ///     "origin": {
        ///         "longitude": 11.111,
        ///         "latitude": 11.111
        ///    },
        ///    "destination": {
        ///         "longitude": 11.111,
        ///         "latitude": 11.111
        ///    },
        ///    "via": [
        ///         {
        ///             "longitude": 11.111,
        ///             "latitude": 11.111
        ///         },
        ///         {
        ///             "longitude": 11.111,
        ///             "latitude": 11.111
        ///         }
        ///    ],
        ///    "originPoiId": "abcd",
        ///    "destPoiId": "abcd",
        ///    "departureTime": 123456, //时间戳
        /// }
        /// ```
        do {
            let json = try T3FJsonUtil.toJson(arguments)

            if let origin = jsonToCoordinate2D(key: "origin", json: json),
                let destination = jsonToCoordinate2D(key: "destination", json: json) {

                var via: [AMapGeoPoint]?
                if let viaArray = json["via"] as? [[String : Double]] {
                    let value = jsonToCoordinate2DArray(json: viaArray)
                    via = value.map({ AMapGeoPoint.location(withLatitude: $0.latitude, longitude: $0.longitude) })
                }

                let originPoiId = json["originPoiId"] as? String
                let destPoiId = json["destPoiId"] as? String

                if let search = search {
                    //构建request
                    let request = AMapDrivingCalRouteSearchRequest()
                    request.strategy = 32 //32：默认，高德推荐，同高德地图APP默认
                    
                    request.origin = AMapGeoPoint.location(withLatitude: origin.latitude, longitude: origin.longitude)
                    request.destination = AMapGeoPoint.location(withLatitude: destination.latitude, longitude: destination.longitude)
                    request.waypoints = via
                    request.originId = originPoiId
                    request.destinationId = destPoiId

                    request.showFieldType = AMapDrivingRouteShowFieldType(rawValue:  AMapDrivingRouteShowFieldType.cost.rawValue |  AMapDrivingRouteShowFieldType.polyline.rawValue | AMapDrivingRouteShowFieldType.tmcs.rawValue) ?? .polyline

                    /// 保持引用
                    strongSelf = self
                    search.delegate = self
                    search.aMapDrivingV2RouteSearch(request)
                }
                else {
                    let response = ["error": T3FMARouteManagerError.mapSearchInitFail.localizedDescription]
                    let value = try? T3FJsonUtil.toString(response)
                    self.result?(value)
                }
            }
            else {
                let response = ["error": T3FMARouteManagerError.dataParseFail.localizedDescription]
                let value = try? T3FJsonUtil.toString(response)
                self.result?(value)
            }
        } catch (let error) {
            let response = ["error": error.localizedDescription]
            let value = try? T3FJsonUtil.toString(response)
            self.result?(value)
        }
    }

    deinit {
        print("deinit route manager")
    }

    private func jsonToCoordinate2D(key: String, json: [String: Any]) -> CLLocationCoordinate2D? {

        guard let value = json[key] as? [String: Any] else { return nil }
        guard let longitude = value["longitude"] as? Double,
              let latitude = value["latitude"] as? Double
        else { return nil }

        return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
    }

    private func jsonToCoordinate2DArray(json: [[String: Any]]) -> [CLLocationCoordinate2D] {

        var array: [CLLocationCoordinate2D] = []

        for ele in json {
            if let longitude = ele["longitude"] as? Double,
               let latitude = ele["latitude"] as? Double {
                array.append(CLLocationCoordinate2D(latitude: latitude, longitude: longitude))
            }
        }

        return array
    }
}

extension T3FMARouteManager: AMapSearchDelegate {

    func onRouteSearchDone(_ request: AMapRouteSearchBaseRequest!, response: AMapRouteSearchResponse!) {

        defer { strongSelf = nil }

        if let routePaths = response.route.paths {
            var routes: [[String : Any]] = []
            for routePath in routePaths {
                /// 预计行驶时间，单位：秒
                let duration = routePath.duration
                /// 起点和终点的距离，单位：米
                let distance = routePath.distance
                /// 道路费用，单位：元
                let tolls = routePath.tolls
                /// 红绿灯数量，单位：个
                let trafficLightCount = routePath.totalTrafficLights
                /// 路线坐标点串
                let polyline = routePath.polyline

                let json = [
                    "duration" : duration,
                    "distance" : distance,
                    "tolls"    : tolls,
                    "trafficLightCount" : trafficLightCount,
                    "polyline" : polyline ?? ""
                ] as [String : Any]

                routes.append(json)
            }
            
            var value: [String: Any] = [:]
            value["routes"] = routes
            let retValue = try? T3FJsonUtil.toString(value)
            self.result?(retValue)
        }
        else {
            let response = ["error": T3FMARouteManagerError.noResult.localizedDescription]
            let value = try? T3FJsonUtil.toString(response)
            self.result?(value)
        }
    }

    func aMapSearchRequest(_ request: Any!, didFailWithError error: Error!) {

        defer { strongSelf = nil }

        let response = ["error": error.localizedDescription]
        let value = try? T3FJsonUtil.toString(response)
        self.result?(value)
    }
}

private enum T3FMARouteManagerError: Error {
    case dataParseFail
    case mapSearchInitFail
    case noResult
}

extension T3FMARouteManagerError: CustomStringConvertible {

    var description: String {
        switch self {
        case .dataParseFail:
            return "数据解析异常"
        case .mapSearchInitFail:
            return "AMapSearchAPI 初始化失败"
        case .noResult:
            return "未查询到步行路线"
        }
    }
}
